<?php
# Interface for the RASS client library.
#
# Copyright (C) 2008 rambla.be
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

/**
 * @file
 * Implementation of the Rass interface class.
 */

require_once dirname(__FILE__) . '/../Raws.php';
require_once dirname(__FILE__) . '/../Util.php';
require_once dirname(__FILE__) . '/Rass/UserFeed.php';
require_once dirname(__FILE__) . '/Rass/UserEntry.php';
require_once dirname(__FILE__) . '/Rass/DirFeed.php';
require_once dirname(__FILE__) . '/Rass/DirEntry.php';
require_once dirname(__FILE__) . '/Rass/DirQuery.php';
require_once dirname(__FILE__) . '/Rass/MetaFeed.php';
require_once dirname(__FILE__) . '/Rass/MetaEntry.php';
require_once dirname(__FILE__) . '/Rass/MetaQuery.php';
require_once dirname(__FILE__) . '/Rass/ItemEntry.php';
require_once dirname(__FILE__) . '/Rass/VocabFeed.php';
require_once dirname(__FILE__) . '/Rass/VocabEntry.php';
require_once dirname(__FILE__) . '/Rass/ExtFeed.php';
require_once dirname(__FILE__) . '/Rass/ExtEntry.php';
require_once dirname(__FILE__) . '/Rass/ExtQuery.php';
require_once dirname(__FILE__) . '/../raws_curl.php';
require_once 'Zend/Http/Response.php';

/**
 * Class containing interface methods for RASS API.
 **/
class Rass extends Raws
{

    public static $namespaces = array(
            'raws' => 'http://rambla.be/raws/ns-metadata/1.0');

    /**
     * Instantiate a Rats object.
     *
     * @param string $user The Rambla username.
     * @param string $pwd The Rambla pwd.
     * @param string $base_uri URI of the RASS server; use 'http://rass.cdn01.rambla.be/' or  http://rass.cdn02.rambla.be/' depending on your account setup.
     * @param string $path Currently not being used; leave null.
     * @param Zend_Http_Client $client Leave null, unless the caller has instantiated his own Zend_Http_Client object.
     * @param string $applicationId Identification string for your client, to be sent in the HTTP headers.
     */
    public function __construct($user = null, $pwd = null, $base_uri = null, $path = null, $client = null, $applicationId = 'MyCompany-MyApp-1.0', $ssl = False)
    {
      if (! $base_uri) {
        $base_uri = "http://rass.cdn01.rambla.be";
      }
      $this->registerPackage('Rass');
      $this->registerPackage('Rass_Extension');
      parent::__construct($user, $pwd, $base_uri, $path, $client, $applicationId, $ssl);
    }

    /**
     * Retrieve an entry containing the RASS user data (GET /user).
     *
     * @return Rass_UserEntry
     */
    public function getUserEntry($className='Rass_UserEntry')
    {
      # user can only update herself, so set the path right
      $uri = safe_raws_uri($this->getBaseUri(), "user", $this->getUser());
      return parent::getEntry($uri, $className);
    }
    
    public function createUser($username, $email, $password)
    {
      # URI to post to
      $uri = safe_raws_uri($this->getBaseUri(), "user");
      // Create a new entry object (short notation for: $newEntry = new Rass_UserEntry();)
      $newEntry = $this->newUserEntry();
      // Create a new userParams object (short notation for: $newParams = new Rass_Extension_Params();)
      $newParams = $this->newUserParams();
      $newParams->username = $this->newUsername($username);
      $newParams->email = $this->newEmail($email);
      $newParams->password = $this->newPassword($password);
      # Create a new userContent object and set it on the entry
      $newEntry->content = $this->newUserContent($newParams);
      # Call app's insertEntry() to send it to the server
      return $this->insertEntry($newEntry, $uri, 'Rass_UserEntry');
    }
    
    public function updateUserEntry($email, $firstname = null, $lastname = null)
    {
      # user can only update herself, so set the path right
      $this->setPath($this->getUser());
      # get the entry
      $entry = $this->getUserEntry();
      # change the values
      $entry->content->params->email->text = $email;
      if ($firstname) {
        $entry->content->params->firstname->text = $firstname;
      }
      if ($lastname) {
        $entry->content->params->lastname->text = $lastname;
      }
      # update the entry
      return $entry->save();
    }
    
    /**
     * Retrieve an entry containing the RASS user data (GET /user).
     *
     * @return Rass_UserEntry
     */
    public function deleteUser($username)
    {
      # URI to delete
      $uri = safe_raws_uri($this->getBaseUri(), "user", $username);
      $this->delete($uri);
    }
    
    /**
     * Retrieve a feed of existing item and/or dir entries inside a RASS dir (GET /dir/{path}).
     *
     * @param string $path The location of the directory for which data is being retrieved.
     * @param Rass_DirQuery $query A Rass_DirQuery that allows passing query-string parameters.
     * @return Rass_DirFeed
     */
    public function getDirFeed($path = null, $query = null, $className='Rass_DirFeed')
    {
      $resource = "dir";
      if ($query) {
        # let the query-obj compose the uri, when present
        $uri = $query->getQueryUrl($this->getBaseUri(), null, $path);
      }
      else {
        # no query obj, compose URI without query-string
        $uri = safe_raws_uri($this->getBaseUri(), $resource, $path);
      }
      return parent::getFeed($uri, $className);
    }

    /**
     * Retrieve a feed of existing item and/or dir entries from a full RASS url.
     *
     * @param string $url The url to retrieve, including query-string args.
     * @return Rass_DirFeed
     */
    public function getDirFeedFromUrl($uri, $className='Rass_DirFeed')
    {
      return parent::getFeed($uri, $className);
    }

    /**
     * Create a new directory (PUT /dir/{path}).
     *
     * @param string $path The location of the directory that needs to be created
     * @param bool $force_create If set to True, POST dir will be used instead of PUT dir => the caller should check the response entry for the actual directory name
     * @return Rass_DirEntry if created
     */
    public function createDir($path, $force_create = False)
    {
      // Set the URI to which the file will be uploaded.
      $base_uri = $this->getBaseUri();
      $uri = safe_raws_uri($base_uri, "dir", $path);
      
      // Create an empty media source => zend throws if null is passed as first param
      require_once "Zend/Gdata/App/Entry.php";
      $src = new Zend_Gdata_App_Entry();

      if ($force_create) {
        $response = $this->post($src, $uri);
      }
      else {
        $response = $this->put($src, $uri);
      }
      if ($response->isSuccessful()) {
        $returnEntry = new Rass_DirEntry($response->getBody());
        $returnEntry->setHttpClient(self::getstaticHttpClient());
        return $returnEntry;
      }
      return $response;
    }
    
    /**
     * Delete an existing directory (DELETE /dir/{path}).
     *
     * @param string $path The location of the directory that needs to be deleted
     */
    public function deleteDir($path, $recursive = False)
    {
      // Set the URI to which the file will be uploaded.
      $base_uri = $this->getBaseUri();
      $uri = safe_raws_uri($base_uri, "dir", $path);
      if ($recursive) {
        $uri = $uri . "?recursive=1";
      }
      $this->delete($uri);
    }

    /**
     * Upload a binary file, creating an item resource instance (PUT /item/{path}).
     *
     * @param string $path The location of the item that needs to be created.
     * @param string $src_location The location of the file that needs to be uploaded on the client machine's filesystem.
     * @return Rass_ItemEntry if created
     */
    public function createItem($path, $src_location)
    {
        // Set the URI to which the file will be uploaded.
        $base_uri = $this->getBaseUri();
        $uri = safe_raws_uri($base_uri, "item", $path);
        
        // Create the media source which describes the file.
        require_once "Zend/Gdata/App/MediaFileSource.php";
        $src = new Zend_Gdata_App_MediaFileSource($src_location);

        $response = $this->put($src, $uri, null, "video/*");
        if ($response->isSuccessful()) {
          $returnEntry = new Rass_ItemEntry($response->getBody());
          $returnEntry->setHttpClient(self::getstaticHttpClient());
          return $returnEntry;
        }
        return $response;
    }

    /**
     * Delete an item on the Rambla CDN.
     *
     * @param string $path The location of the file that needs to be deleted (DELETE /item/{path}).
     */
    public function deleteItem($path) {
      // Set the URI to which the file will be uploaded.
      $base_uri = $this->getBaseUri();
      $uri = safe_raws_uri($base_uri, "item", $path);
      $this->delete($uri);
    }

    public function getItemHeader($path) {
      $client = $this->getHttpClient();

      $base_uri = $this->getBaseUri();
      $uri = safe_raws_uri($base_uri, "item", $path);
      $client->setUri($uri);
      
      $response = $client->request('HEAD');
      if (($response->getStatus() != 404) and (!$response->isSuccessful())) {
          require_once 'Zend/Gdata/App/HttpException.php';
          $exception = new Zend_Gdata_App_HttpException('Expected response code 200 or 404, got ' . $response->getStatus());
          $exception->setResponse($response);
          throw $exception;
      }
      if ($response->getStatus() != 200) {
        return null;
      }
      return $response;
    }
    
    /**
     * DEPRECATED: use getItemFromCDN() instead !!!!
     * Retrieve an existing media item (GET /item/{path}/) from RASS and store it in a location on the local machine.
     *
     * @param string $path The path of the item on the RASS server (to be added to "/item/").
     * @param string $tgt_location_local Path (including filename + extension) of where to store the file locally.
     * @return $response object in case of success, otherwise exception is thrown
     */
    public function getItem($path, $tgt_location_local) {
      
      # check if tgt_location_local is writable
      $res = fopen($tgt_location_local, 'wb+');
      if (! $res) {
        require_once 'Zend/Exception.php';
        throw new Zend_Exception("Unable to open file location '" . $tgt_location_local . "' for writing.");
      }
      fclose($res);

      // Create a connection object for communication with RASS
      $rc = new RawsConnection($this->_user, $this->_pwd);
      # make the full uri for the curl client
      $uri = rtrim($this->_base_uri, "/");
      $uri = $uri . "/" . "item/";
      $uri = $uri . ltrim($path, "/");

      # send the request
      $rc->sendRequest($uri, "GET", $tgt_location_local);
      # create a Zend_Http_Response and set it on our Zend Http client (for conformance with other methods)
      $response = $this->_setCurlResponseOnZendClient($rc);

      if ($rc->hasSucceeded()) {
        return $response;
      }
      else {
        require_once 'Zend/Gdata/App/HttpException.php';
        $exception = new Zend_Gdata_App_HttpException('Expected response code 200, got ' . $response->getStatus());
        $exception->setResponse($response);
        throw $exception;
      }
    }
    
    /**
     * Uses the enclosure link inside the entry to download the file directly from the CDN.
     *
     * @param string $entry An item entry.
     * @param string $tgt_location_local Path (including filename + extension) of where to store the file locally.
     * @return $response object in case of success, otherwise exception is thrown
     */
    public function getItemFromCDN($entry, $tgt_location_local) {
      
      # check if tgt_location_local is writable
      $res = fopen($tgt_location_local, 'wb+');
      if (! $res) {
        require_once 'Zend/Exception.php';
        throw new Zend_Exception("Unable to open file location '" . $tgt_location_local . "' for writing.");
      }
      fclose($res);

      $encl_url = get_enclosure_url_from_entry($entry);
      if (! $encl_url)  {
        require_once 'Zend/Exception.php';
        throw new Zend_Exception("Unable to find enclosure link.");
      }
      
      // Create a connection object for communication with RASS
      $rc = new RawsConnection();
      # send the request
      $rc->sendRequest($encl_url, "GET", $tgt_location_local);
      # create a Zend_Http_Response and set it on our Zend Http client (for conformance with other methods)
      $response = $this->_setCurlResponseOnZendClient($rc);

      if ($rc->hasSucceeded()) {
        return $response;
      }
      else {
        require_once 'Zend/Gdata/App/HttpException.php';
        $exception = new Zend_Gdata_App_HttpException('Expected response code 200, got ' . $response->getStatus());
        $exception->setResponse($response);
        throw $exception;
      }
    }
    
    /**
     * Upload a binary file using curl (= streaming upload), creating an item resource instance (PUT /item/{path}).
     *
     * @param string $path The location of the item that needs to be created.
     * @param string $src_location The location of the file that needs to be uploaded on the client machine's filesystem.
     * @return Rass_ItemEntry if created
     */
    public function createItemCurl($path, $src_location)
    {
      // Create a connection object for communication with RASS
      $rc = new RawsConnection($this->_user, $this->_pwd);
      # make the full uri for the curl client
      $uri = rtrim($this->_base_uri, "/");
      $uri = $uri . "/" . "item/";
      $uri = $uri . ltrim($path, "/");
      
      # send the request
      $rc->sendRequest($uri, "PUT", $src_location, "video/*", "application/atom+xml");
      # create a Zend_Http_Response and set it on our Zend Http client (for conformance with other methods)
      $response = $this->_setCurlResponseOnZendClient($rc);
      
      if ($rc->hasSucceeded()) # if succeeded, process the entry's body and return it
      { 
        $returnEntry = new Rass_ItemEntry($rc->getBody());
        $returnEntry->setHttpClient(self::getstaticHttpClient());
        return $returnEntry;
      }
      else # throw an exception in case of failure
      {
        require_once 'Zend/Gdata/App/HttpException.php';
        $exception = new Zend_Gdata_App_HttpException('Expected response code 201, got ' . $response->getStatus());
        $exception->setResponse($response);
        throw $exception;
      }
    }
    
    protected function _setCurlResponseOnZendClient($rc) 
    {
      $headers = $rc->getHeader();
      // $a_head = array();
      // if ($headers) {
      //   $a_head = explode("\n", $headers);
      // }
      $code    = Zend_Http_Response::extractCode($headers);
      $headers = Zend_Http_Response::extractHeaders($headers);
      
      // $response = new Zend_Http_Response($rc->getHttpCode(), $a_head, $rc->getBody());
      $response = new Zend_Http_Response($code, $headers, $rc->getBody());
      $this->getHttpClient()->setResponse($response);
      return $response;
    }

    /**
     * Upload a binary file using RATS POST method (POST /item/{path}).
     *
     * @param string $dirpath The location of the directory in which the item needs to be stored.
     * @param string $filename The (suggested) filename for the item on the RASS server.
     * @param string $src_location The location of the file that needs to be uploaded on the client machine's filesystem.
     * @return Rass_ItemEntry if created
     */
    public function postItem($dirpath, $filename, $src_location)
    {
      // Set the URI to which the file will be uploaded.
      $base_uri = $this->getBaseUri();
      $uri = safe_raws_uri($base_uri, "item", $dirpath);
      
      // Create the media source which describes the file.
      require_once "Zend/Gdata/App/MediaFileSource.php";
      $src = new Zend_Gdata_App_MediaFileSource($src_location);

      # handle the slug header, send POST request, and remove slug header again
      try {
        $src->setSlug($filename);
        $response = $this->post($src, $uri, null, "video/*");
      }
      catch(Zend_Gdata_App_Exception $e) {
        $this->unsetSlugHeader();
        throw $e;
      }
      $this->unsetSlugHeader();

      if ($response->isSuccessful()) {
        $returnEntry = new Rass_ItemEntry($response->getBody());
        $returnEntry->setHttpClient(self::getstaticHttpClient());
        return $returnEntry;
      }
      return $response;
    }
    
    /**
     * Retrieve a feed of existing vocabularies (GET /vocab/{username}/).
     *
     * @param string $name The vocabulary name.
     * @return Rass_VocabFeed
     */
    public function getVocabFeed($className='Rass_VocabFeed')
    {
      # pre-pend username to location to get meta path
      $vocab_path = "/" . $this->_user;
      # no query obj, compose URI without query-string
      $uri = safe_raws_uri($this->getBaseUri(), "vocab", $vocab_path);
      return parent::getFeed($uri, $className);
    }
    
    /**
     * Retrieve an existing vocabulary entry (GET /vocab/{username}/{vocab_name}/).
     *
     * @param string $name The vocabulary name.
     * @return Rass_VocabFeed
     */
    public function getVocabEntry($name)
    {
      # pre-pend username to location to get meta path
      $vocab_path = "/" . $this->_user . "/" . $name;
      # no query obj, compose URI without query-string
      $uri = safe_raws_uri($this->getBaseUri(), "vocab", $vocab_path);
      return parent::getEntry($uri, 'Rass_VocabEntry');
    }
    
    /**
     * Create a new vocabulary (POST /vocab/{username}/).
     *
     * @param string $name The vocabulary name.
     * @param string $xml_namespace The vocabulary's XML namespace.
     * @param string $description The vocabulary description.
     * @return Rass_VocabFeed
     */
    public function createVocab($name, $xml_namespace, $description = null)
    {
      # pre-pend username to location to get meta path
      $vocab_path = "/" . $this->_user . "/";
      # URI to post to
      $uri = safe_raws_uri($this->getBaseUri(), "vocab", $vocab_path);

      $newEntry = $this->newVocabEntry();
      $newParams = $this->newVocabParams();
      $newParams->name = $this->newName($name);
      $newParams->xml_namespace = $this->newXmlNamespace($xml_namespace);
      $newParams->description = $this->newDescription($description);
      $newEntry->content = $this->newVocabContent($newParams);
      
      # Call app's insertEntry() to send it to the server
      return $this->insertEntry($newEntry, $uri, 'Rass_VocabEntry');
    }
    
    /**
     * Update an existing vocabulary (POST /vocab/{username}/{vocab_name}/).
     *
     * @param string $name The vocabulary name.
     * @param string $xml_namespace The vocabulary's XML namespace.
     * @param string $description The vocabulary description.
     * @return Rass_VocabFeed
     */
    public function updateVocab($name, $xml_namespace, $description = null)
    {
      # pre-pend username to location to get meta path
      $vocab_path = "/" . $this->_user . "/" . $name . "/";
      # URI to post to
      $uri = safe_raws_uri($this->getBaseUri(), "vocab", $vocab_path);

      $newEntry = $this->newVocabEntry();
      $newParams = $this->newVocabParams();
      $newParams->name = $this->newName($name);
      $newParams->xml_namespace = $this->newXmlNamespace($xml_namespace);
      $newParams->description = $this->newDescription($description);
      $newEntry->content = $this->newVocabContent($newParams);
      
      # Call app's insertEntry() to send it to the server
      return $this->insertEntry($newEntry, $uri, 'Rass_VocabEntry');
    }

    /**
     * Delete an existing vocabulary (POST /vocab/{username}/{vocab_name}/).
     *
     * @param string $name The vocabulary name.
     * @throws Zend_Gdata_App_Exception
     */
    public function deleteVocab($name)
    { 
      # pre-pend username to location to get meta path
      $vocab_path = "/" . $this->_user . "/" . $name . "/";
      $uri = safe_raws_uri($this->getBaseUri(), "vocab", $vocab_path);
      $this->delete($uri);
    }
      
    /**
     * Retrieve a feed of existing metadata (GET /meta/{username}/{path}).
     *
     * @param string $path The location of the directory for which metadata is being retrieved.
     * @param Rass_DirQuery $query A Rass_DirQuery that allows passing query-string parameters.
     * @return Rass_DirFeed
     */
    public function getMetaFeed($path = null, $query = null, $className='Rass_MetaFeed')
    {
      # pre-pend username to location to get meta path
      $meta_path = "/" . $this->_user . "/";
      if ($path) {
        $meta_path .= ltrim($path, '/');
      }
      if ($query) {
        # let the query-obj compose the uri, when present
        $uri = $query->getQueryUrl($this->getBaseUri(), null, $meta_path);
      }
      else {
        # no query obj, compose URI without query-string
        $uri = safe_raws_uri($this->getBaseUri(), "meta", $meta_path);
      }
      return parent::getFeed($uri, $className);
    }

    /**
     * Retrieve an existing meta entry (GET /meta/{username}/{path}).
     *
     * @param string $uri The URI that is pointing to the meta entry instance.
     * @return Rats_OutputEntry
     */
    public function getMetaEntry($path, $query = null)
    {
      # pre-pend username to location to get meta path
      $meta_path = "/" . $this->_user . "/";
      if ($path) {
        $meta_path .= ltrim($path, '/');
      }
      if ($query) {
        # let the query-obj compose the uri, when present
        $uri = $query->getQueryUrl($this->getBaseUri(), null, $meta_path);
      }
      else {
        # no query obj, compose URI without query-string
        $uri = safe_raws_uri($this->getBaseUri(), "meta", $meta_path);
      }
      return parent::getEntry($uri, 'Rass_MetaEntry');
    }


    /**
     * Set tag(s) on a RASS item or dir resource.
     *
     * @param Rass_MetaEntry $entry An existing Rass_MetaEntry resource.
     * @param array $tag_array array of Rass_Extension_Tag objects
     * @param array $meta_array array of Rass_Extension_Meta objects
     * @return Rass_MetaEntry The entry returned from the server
     * @throws Zend_Gdata_App_Exception
     */
    public function addMetadata($entry, $tag_array, $meta_array)
    {
      if ($tag_array) {
        $entry->content->params->tag = array_merge($entry->content->params->tag, $tag_array);
      }
      if ($meta_array) {
        $entry->content->params->meta = array_merge($entry->content->params->meta, $meta_array);
      }
      # Call app's insertEntry() to send it to the server
      return $this->insertEntry($entry, $entry->id->text, 'Rass_MetaEntry');
    }


    /**
     * Set tag(s) on a RASS item or dir resource.
     *
     * @param Rass_MetaEntry $entry An existing Rass_MetaEntry resource.
     * @param array $tag_array array of Rass_Extension_Tag objects
     * @param array $meta_array array of Rass_Extension_Meta objects
     * @return Rass_MetaEntry The entry returned from the server
     * @throws Zend_Gdata_App_Exception
     */
    public function setMetadata($entry, $tag_array, $meta_array)
    {
      if (! $tag_array) {
        $tag_array = array();
      }
      $entry->content->params->tag = $tag_array;
      if (! $meta_array) {
        $meta_array = array();
      }
      $entry->content->params->meta = $meta_array;
      # Call app's insertEntry() to send it to the server
      return $this->insertEntry($entry, $entry->id->text, 'Rass_MetaEntry');
    }
    
    /**
     * Create or overwrite a RASS meta entry.
     *
     * @param string $path The location of the file or directory for which metadata is being set.
     * @param array $tag_array array of Rass_Extension_Tag objects
     * @param array $meta_array array of Rass_Extension_Meta objects
     * @return Rass_MetaEntry The entry returned from the server
     * @throws Zend_Gdata_App_Exception
     */
    public function setMetadataFromPath($path, $tag_array, $meta_array = null)
    {
      # pre-pend username to location to get meta path
      $meta_path = "/meta/" . $this->_user . "/";
      if ($path) {
        $meta_path .= ltrim($path, '/');
      }
      # URI to post to
      $uri = safe_raws_uri($this->getBaseUri(), $meta_path);
      // Create a new entry object (short notation for: $newEntry = new Rass_MetaEntry();)
      $newEntry = $this->newMetaEntry();
      // Create a new metaParams object (short notation for: $newParams = new Rass_Extension_Params();)
      $newParams = $this->newMetaParams();
      $newParams->tag = $tag_array;
      $newParams->meta = $meta_array;
      
      # Create a new metaContent object and set it on the entry
      $newEntry->content = $this->newMetaContent($newParams);
      # Call app's insertEntry() to send it to the server
      return $this->insertEntry($newEntry, $uri, 'Rass_MetaEntry');
    }

    /**
     * Delete the metadata for an existing RASS item or dir resource.
     *
     * @param string $path The location of the file or directory for which metadata is being deleted.
     * @throws Zend_Gdata_App_Exception
     */
    public function deleteMetaEntry($entry)
    { 
      $this->delete($entry->get_self_url());
    }
    
    /**
     * Delete the metadata for an existing RASS item or dir resource.
     *
     * @param Rass_MetaEntry $entry An existing Rass_MetaEntry resource.
     * @throws Zend_Gdata_App_Exception
     */
    public function deleteMetaEntry_from_path($path)
    {
      # pre-pend username to location to get meta path
      $meta_path = "/meta/" . $this->_user . "/";
      if ($path) {
        $meta_path .= ltrim($path, '/');
      }
      # URI to send delete request to
      $uri = safe_raws_uri($this->getBaseUri(), $meta_path);
      $this->delete($uri);
    }
 
    // ## IF meta PUT IS EVER IMPLEMENTED
    // public function updateMetaEntry($entry)
    // {
    //   # user can only update herself, so set the path right
    //   $this->setPath($entry->id->text);
    //   # update the entry
    //   return $entry->save();
    // }

    /**
     * Rambla-internal method to retrieve dir sizes
     *
     * @param string $username Name of the CDN user.
     */
    public function getSizeHeader($username) {
      $client = $this->getHttpClient();

      $base_uri = $this->getBaseUri();
      $uri = safe_raws_uri($base_uri, "size", $username);
      $client->setUri($uri);
      
      $response = $client->request('HEAD');
      if (($response->getStatus() != 404) and (!$response->isSuccessful())) {
          require_once 'Zend/Gdata/App/HttpException.php';
          $exception = new Zend_Gdata_App_HttpException('Expected response code 200 or 404, got ' . $response->getStatus());
          $exception->setResponse($response);
          throw $exception;
      }
      if ($response->getStatus() != 200) {
        return null;
      }
      return $response;
    }
    
    /**
     * Retrieve an external atom feed (GET /ext/atom/{username}/{path}).
     *
     * @param string $path The location of the directory for which metadata is being retrieved.
     * @param Rass_DirQuery $query A Rass_DirQuery that allows passing query-string parameters.
     * @return Rass_DirFeed
     */
    public function getExtFeed($path = null, $query = null, $className='Rass_MetaFeed')
    {
      # pre-pend username to location to get meta path
      $meta_path = "/" . $this->_user . "/";
      if ($path) {
        $meta_path .= ltrim($path, '/');
      }
      if ($query) {
        # let the query-obj compose the uri, when present
        $uri = $query->getQueryUrl($this->getBaseUri(), null, $meta_path);
      }
      else {
        # no query obj, compose URI without query-string
        $uri = safe_raws_uri($this->getBaseUri(), "ext/atom", $meta_path);
      }
      return parent::getFeed($uri, $className);
    }

    /**
     * Set files that are related (same content, different formats).
     *
     * @param $array Array containing the relative paths to files on the CDN that are related.
     * @return Zend_Http_Response containing a json encoded list of related files
     * @see https://rampubwiki.wiki.rambla.be/RASS_related_resource
     */
    public function setRelated($related_files)
    {
      $client = $this->getHttpClient();
      $base_uri = $this->getBaseUri();
      $uri = safe_raws_uri($base_uri, "related");
      $client->setUri($uri);

      $json_input = array("related" => $related_files);
      $json = json_encode($json_input);
      $response = $client->setRawData($json, 'application/json')->request('POST');
      
      return $response;
    }
    
    /**
     * Get files that are related to a given file on the CDN (same content, different formats).
     *
     * @param filepath Relative path to a file on the CDN, for which related files will be retrieved.
     * @return Zend_Http_Response containing a json encoded list of related files
     * @see https://rampubwiki.wiki.rambla.be/RASS_related_resource
     */
    public function getRelated($filepath)
    {
      $client = $this->getHttpClient();
      $base_uri = $this->getBaseUri();
      $uri = safe_raws_uri($base_uri, "related", $path);
      $client->setUri($uri);

      $response = $client->request('GET');
      return $response;
    }
    
    /**
     * Rambla-internal method to create demo files for adaptive streaming
     *
     * @param string $username Name of the CDN user.
     */
    public function getAdaptiveDemo($username) {
      $client = $this->getHttpClient();

      $base_uri = $this->getBaseUri();
      $uri = safe_raws_uri($base_uri, "adaptive-demo", $username);
      $client->setUri($uri);
      
      $response = $client->request('GET');
      if (($response->getStatus() != 404) and (!$response->isSuccessful())) {
          require_once 'Zend/Gdata/App/HttpException.php';
          $exception = new Zend_Gdata_App_HttpException('Expected response code 200 or 404, got ' . $response->getStatus());
          $exception->setResponse($response);
          throw $exception;
      }
      if ($response->getStatus() != 200) {
        return null;
      }
      return $response;
    }
    
}
